﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Windows.Media;
using System.Windows.Media.Media3D;

namespace PlyViewer
{
    public static class BinaryPlyReader
    {
        public static PlyPointCloud ReadBinaryPlyFile(string filePath)
        {
            var pointCloud = new PlyPointCloud();
            pointCloud.FileName = Path.GetFileName(filePath);

            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read))
            using (var reader = new BinaryReader(stream))
            {
                string line;
                bool readingHeader = true;
                int vertexCount = 0;
                bool hasColor = false;
                bool isLittleEndian = true;

                // 读取文件头
                while (readingHeader && (line = ReadLine(reader)) != null)
                {
                    line = line.Trim();

                    if (line.StartsWith("format"))
                    {
                        var parts = line.Split(' ');
                        isLittleEndian = parts[1] != "binary_big_endian";
                    }
                    else if (line.StartsWith("element vertex"))
                    {
                        var parts = line.Split(' ');
                        vertexCount = int.Parse(parts[2]);
                    }
                    else if (line.Contains("red") || line.Contains("green") || line.Contains("blue"))
                    {
                        hasColor = true;
                    }
                    else if (line == "end_header")
                    {
                        readingHeader = false;
                    }
                }

                // 读取二进制数据
                for (int i = 0; i < vertexCount; i++)
                {
                    // 读取坐标（假设是float类型）
                    float x = ReadFloat(reader, isLittleEndian);
                    float y = ReadFloat(reader, isLittleEndian);
                    float z = ReadFloat(reader, isLittleEndian);

                    pointCloud.Points.Add(new Point3D(x, y, z));

                    // 读取颜色
                    if (hasColor)
                    {
                        byte r = reader.ReadByte();
                        byte g = reader.ReadByte();
                        byte b = reader.ReadByte();
                        pointCloud.Colors.Add(Color.FromRgb(r, g, b));
                    }
                    else
                    {
                        pointCloud.Colors.Add(Colors.White);
                    }
                }
            }

            return pointCloud;
        }

        private static string ReadLine(BinaryReader reader)
        {
            var bytes = new List<byte>();
            byte b;
            while ((b = reader.ReadByte()) != (byte)'\n')
            {
                if (b != (byte)'\r')
                    bytes.Add(b);
            }
            return Encoding.ASCII.GetString(bytes.ToArray());
        }

        private static float ReadFloat(BinaryReader reader, bool isLittleEndian)
        {
            byte[] bytes = reader.ReadBytes(4);
            if (BitConverter.IsLittleEndian != isLittleEndian)
            {
                Array.Reverse(bytes);
            }
            return BitConverter.ToSingle(bytes, 0);
        }
    }
}